using System;

namespace Noise
{
    public static class Gradient
    {
        private static readonly int[] grads1 = 
        {
            1, 2, 3, 4, 5, 6, 7, 8
        };

        private static readonly int[,] grads2 = 
        {
            { 1,  1 }, { 1, -1 }, {-1,  1 }, {-1, -1 },
            { 1,  0 }, { 0,  1 }, {-1,  0 }, { 0, -1 },
        };

        private static readonly int[,] grads3 = 
        {
            { 1,  1,  0 }, {-1,  1,  0 }, { 1, -1,  0 }, {-1, -1,  0 },
            { 1,  0,  1 }, {-1,  0,  1 }, { 1,  0, -1 }, {-1,  0, -1 },
            { 0,  1,  1 }, { 0, -1,  1 }, { 0,  1, -1 }, { 0, -1, -1 },
            { 1,  1,  0 }, { 0, -1,  1 }, {-1,  1,  0 }, { 0, -1, -1 }
        };

        public static void Grad1(int perm, out int i)
        {
            int h = perm&7;
            i = ((perm&8)==0) ? grads1[h] : -grads1[h];
        }

        public static void Grad2(int perm, out int i, out int j)
        {
            int h = perm&7;
            i = grads2[h, 0];
            j = grads2[h, 1];
        }

        public static void Grad3(int perm, out int i, out int j, out int k)
        {
            int h = perm&15;
            i = grads3[h, 0];
            j = grads3[h, 1];
            k = grads3[h, 2];
        }

        public static float Dot1(int perm, float x)
        {
            int h = perm&7;
            return ((perm&8)==0) ? grads1[h]*x : -grads1[h]*x;
        }

        public static float Dot2(int perm, float x, float y)
        {
            int h = perm&7;
            return grads2[h, 0]*x + grads2[h, 1]*y;
        }

        public static float Dot3(int perm, float x, float y, float z)
        {
            int h = perm&15;
            return grads3[h, 0]*x + grads3[h, 1]*y + grads3[h, 2]*z;
        }
    }
}